package com.shopping.common.core.util;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @program: shopping-mall
 * @ClassName JwtConfig
 * @description:    jwt令牌配置
 * @author: zlw
 * @create: 2024-04-10 22:24
 * @Version 1.0
 **/

@Slf4j
public class JwtUtil {

    /**
     * Token前缀
     */
    private static final String TOKEN_PREFIX = "Bearer ";

    /**
     * 过期时间(一小时有效期)
     */
    private static final long EXPIRE_DATE = 60 * 60 * 1000;

    private static final String CLAIM_KEY_CREATEDTIME = "createdTime";

    private static final String TOKEN_SIGN_KEY = "sp-mall-sign-key";

    private static final Long REFRESH_TOKEN_INTERVAL = 300000L;

    public static String generateToken(Map<String,Object> claims,long expiretionMillisecond,String signingKey){
        //赋值创建时间
        long createTime = System.currentTimeMillis();
        claims.put(CLAIM_KEY_CREATEDTIME,createTime);
        //过期时间
        Date date = new Date(System.currentTimeMillis() + expiretionMillisecond);
        //秘钥及加密算法
        Algorithm algorithm = Algorithm.HMAC256(signingKey);
        //设置头部信息
        Map<String, Object> header = new HashMap<>();
        header.put("type","JWT");
        header.put("alg","HS256");
        //携带username,password信息,生成签名
        String token = JWT.create()
                .withHeader(header)
                .withClaim("claims",claims)
                .withExpiresAt(date)
                .sign(algorithm);
        return TOKEN_PREFIX + token;
    }

    public static DecodedJWT parseToken(String token){
            String tokenKey = token.substring(TOKEN_PREFIX.length());
            DecodedJWT decode = null;
            try{
                decode = JWT.decode(tokenKey);
                return decode;
        }catch (Exception e){
                log.error("Token Expired",e);
        }
        return decode;
    }

    /**
     * 验证token
     * @param token 需要验证的toekn
     * @return
     */
    public static boolean  verifyToken(String token,String tokenSignKey){
        try {
            Algorithm algorithm = Algorithm.HMAC256(tokenSignKey);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token.substring(TOKEN_PREFIX.length()));
            return true;
        }catch (Exception e){
            return false;
        }
    }

    /**
     * 判断解密后的Token payload是否需要被强制刷新，如果需要,则调用generateToken方法重新生成Token。
     * @param claims
     * @return
     */
    public static boolean needToRefresh(Claim claims){
        if(claims == null){
            return false;
        }
        Long createTime = (Long) claims.asMap().get(CLAIM_KEY_CREATEDTIME);
        long l1 = System.currentTimeMillis();
        long l = l1 - createTime;
        return createTime == null  || l  > REFRESH_TOKEN_INTERVAL;
    }

    /**
     * 判断令牌是否过期
     * @param decodedJWT
     * @return
     */
    public static boolean isNullOrExpired(DecodedJWT decodedJWT){
        return decodedJWT == null || decodedJWT.getExpiresAt().before(new Date());
    }
    public static void main(String[] args) {
//        时间戳验证
        long nowTime = System.currentTimeMillis();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date1 = new Date(nowTime);
        Date date2 = new Date(nowTime + 30 * 60 * 1000);
        String format1 = sf.format(date1);
        String format2 = sf.format(date2);
        System.out.println(format1);
        System.out.println(format2);

        //jwt测试
//        String userName = "admin";
//        String passWord = "123456";
//        String userName2 = "root";
//        String passWord2 = "123456";
        HashMap<String,Object> claims = new HashMap<>();
        claims.put("sessionId", UUID.randomUUID().toString());
        String token = generateToken(claims,86400,TOKEN_SIGN_KEY);
//        String token2 = generateToken(userName2, passWord2);
        System.out.println(token);
        String verifyToken = token.substring(TOKEN_PREFIX.length());
//        System.out.println(token2);
        DecodedJWT decodedJWT = parseToken(token);
        Claim claim = decodedJWT.getClaim("claims");
        boolean b = verifyToken(verifyToken,TOKEN_SIGN_KEY);
        Map<String, Object> map = claim.asMap();
        Long createTime = (Long) map.get(CLAIM_KEY_CREATEDTIME);
        System.out.println(claim);
//        boolean b2 = verifyToken(token2);
//        System.out.println(b);
//        System.out.println(b2);
    }
}
